using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace Utility.Threading
{
    public enum TaskState
    {
        Ready,
        Running,
        Complete,
        Cancelled,
    } 
 
    public abstract class Task<T_ARG, T_RES> : IDisposable
    {
        #region Private Attributes.

        private BackgroundWorker backgroundWorker; 

        #endregion

        #region Public Attributes

        private T_ARG argument;
        public T_ARG Argument
        {
            get { return argument; }
            set { argument = value; }
        }

        private T_RES result;
        public T_RES Result
        {
            get { return result; }
            set { result = value; }
        }

        private bool isRunning;
        public bool IsRunning
        {
            get { return isRunning; }
            set { isRunning = value; }
        }

        private TaskState state;
        public TaskState State
        {
            get { return state; }
            set { state = value; }
        } 

        #endregion

        #region Constructors & Destructors

        public Task()
        {
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.WorkerSupportsCancellation = true;

            backgroundWorker.DoWork += ProgressStarted;
            backgroundWorker.ProgressChanged += ProgressChanged;
            backgroundWorker.RunWorkerCompleted += ProgressCompleted;
            state = TaskState.Ready;
        }

        void IDisposable.Dispose()
        {
            if (IsBusy())
            {
                Cancel();
            }
            backgroundWorker.Dispose();
        } 

        #endregion

        #region Public Methods

        public virtual void ProgressReport(int reportPercentage)
        {
            backgroundWorker.ReportProgress(reportPercentage);
        }

        public bool IsBusy()
        {
            return backgroundWorker.IsBusy;
        }
        public bool IsCancelled()
        {
            return backgroundWorker.CancellationPending;
        }

        public void Cancel()
        {
            backgroundWorker.CancelAsync();
        }

        public virtual void Run(T_ARG argument)
        {
            state = TaskState.Running;
            Argument = argument;
            if (argument == null)
            {
                backgroundWorker.RunWorkerAsync();
            }
            else
            {
                backgroundWorker.RunWorkerAsync(argument);
            }
        }

        public abstract void ProgressStarted(object sender, DoWorkEventArgs e);
        public abstract void ProgressChanged(object sender, ProgressChangedEventArgs e);
        public abstract void ProgressCompleted(object sender, RunWorkerCompletedEventArgs e); 

        #endregion
    }
}